package com.agger.harmonyosthemeseditor.intelligent;

import ohos.agp.colors.HsvColor;
import ohos.agp.colors.RgbColor;
import ohos.app.AbilityContext;
import ohos.media.image.PixelMap;
import ohos.media.image.common.*;
import ohos.system.version.SystemVersion;

import java.io.File;
import java.lang.reflect.Method;
import java.util.List;

public class IconManager
{

    public static boolean isAlphaImage(PixelMap mPixelMap)
    {
        try
        {
            System.gc();
            PixelMap pixelMap = ResizeImage(mPixelMap, 30,30);
            for (int h = 0; h < 30; h++)
            {
                for (int w = 0; w < 30; w++)
                {
                    if(new RgbColor(pixelMap.readPixel(new Position(w, h))).getAlpha()<=0f)
                        return true;
                }
            }
            return false;
        }catch (Exception e) { return false;}
    }

    public static PixelMap getVirtualBackground(int mColor)
    {
        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.size = new Size(1,1);
        initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
        initializationOptions.editable = true;
        PixelMap nPixelMap = PixelMap.create(initializationOptions);
        nPixelMap.writePixel(new Position(0,0),HsvColor.toColor(255,ColorManager.getHsvBox(mColor).getHue(), 18f, 100f));
        return ResizeImage(nPixelMap,192,192);
    }

    public static PixelMap grayForPixelMap(PixelMap mPixelMap)
    {
        ImageInfo mImageInfo = mPixelMap.getImageInfo();
        int mWidth = mImageInfo.size.width;
        int mHeight = mImageInfo.size.height;
        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.size = new Size(mWidth,mHeight);
        initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
        initializationOptions.editable = true;
        PixelMap nPixelMap = PixelMap.create(initializationOptions);
        for (int h = 0; h < mHeight; h++)
        {
            for (int w = 0; w < mWidth; w++)
            {
                RgbColor c = RgbColor.fromArgbInt(mPixelMap.readPixel(new Position(w,h)));
                int value = (c.getRed() + c.getGreen() + c.getBlue()) / 3;
                int Red = (int)(value * (1f + (255f - 128f) / 128f) + 0.5f);
                int Green = (int)(value * (1f + (125f - 128f) / 128f) + 0.5f);
                int Blue = (int)(value * (1f + (125f - 128f) / 128f) + 0.5f);
                if (Red > 255) Red = 255;
                if (Red < 0) Red = 0;
                if (Green > 255f) Green = 255;
                if (Green < 0f) Green = 0;
                if (Blue > 255f) Blue = 255;
                if (Blue < 0f) Blue = 0;
                nPixelMap.writePixel(new Position(w,h),new RgbColor(Red,Green,Blue,c.getAlpha()).asArgbInt());
            }
        }
        return nPixelMap;
    }

    public static PixelMap maskForIcon(PixelMap mask,PixelMap mPixelMap)
    {
        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.size = new Size(192,192);
        initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
        initializationOptions.editable = true;
        PixelMap nPixelMap = PixelMap.create(initializationOptions);
        for (int h = 0; h < 192; h++)
        {
            for (int w = 0; w < 192; w++)
            {
                RgbColor c = RgbColor.fromArgbInt(mPixelMap.readPixel(new Position(w,h)));
                int A = (int)(c.getAlpha()*(RgbColor.fromArgbInt(mask.readPixel(new Position(w,h))).getAlpha()/255f));
                nPixelMap.writePixel(new Position(w,h),new RgbColor(c.getRed(),c.getGreen(),c.getBlue(),A).asArgbInt());
            }
        }
        return nPixelMap;
    }

    public static PixelMap maskForIcon(PixelMap mask,PixelMap mPixelMap,float alpha)
    {
        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.size = new Size(192,192);
        initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
        initializationOptions.editable = true;
        PixelMap nPixelMap = PixelMap.create(initializationOptions);
        for (int h = 0; h < 192; h++)
        {
            for (int w = 0; w < 192; w++)
            {
                RgbColor c = RgbColor.fromArgbInt(mPixelMap.readPixel(new Position(w,h)));
                int A = (int)(c.getAlpha()*(RgbColor.fromArgbInt(mask.readPixel(new Position(w,h))).getAlpha()/255f)*alpha);
                nPixelMap.writePixel(new Position(w,h),new RgbColor(c.getRed(),c.getGreen(),c.getBlue(),A).asArgbInt());
            }
        }
        return nPixelMap;
    }

    public static PixelMap rebuildIcon(PixelMap mPixelMap)
    {
        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.size = new Size(192,192);
        initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
        initializationOptions.editable = true;
        PixelMap nPixelMap = PixelMap.create(initializationOptions);
        for (int h = 0; h < 192; h++)
        {
            for (int w = 0; w < 192; w++)
            {
                RgbColor icon_pixel = RgbColor.fromArgbInt(mPixelMap.readPixel(new Position(w,h)));
                float TempAlpha;

                ColorManager.HsvBox hsvBox = ColorManager.getHsvBox(mPixelMap.readPixel(new Position(w,h)));
                float H = hsvBox.getHue(), S = hsvBox.getSaturation(), V = hsvBox.getValue();

                float V_Alpha = V / 80f;
                if (V_Alpha > 1f) V_Alpha = 1f; else if (V_Alpha < 0f) V_Alpha = 0f;
                if (S > 50f && V > 60f) TempAlpha = 1f;
                else if (S > 50f && V <= 60f) TempAlpha = V_Alpha * 0.8f / (Math.min((0.5f + ((S - 50f) / 200f)), 0.66f));
                else if (S <= 50f && V > 76f) TempAlpha = 1f;
                else if (S <= 50f && V <= 76f) TempAlpha = V_Alpha * 0.8f / 0.72f;
                else TempAlpha = 1f;
                if (TempAlpha > 1f) TempAlpha = 1f; else if (TempAlpha < 0f) TempAlpha = 0f;
                if (S < 50f)
                {
                    if (V >= 80f && S < 26f) {TempAlpha = 0f; }
                }
                int colorValue = HsvColor.toColor((int)(icon_pixel.getAlpha()*TempAlpha),H,S,V);
                nPixelMap.writePixel(new Position(w,h),colorValue);
            }
        }
        return nPixelMap;
    }

    public static PixelMap colorfulIcon(int mColor,PixelMap mPixelMap)
    {
        PixelMap pixelMap = rebuildIcon(mPixelMap);
        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.size = new Size(192,192);
        initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
        initializationOptions.editable = true;
        PixelMap nPixelMap = PixelMap.create(initializationOptions);
        for (int h = 0; h < 192; h++)
        {
            for (int w = 0; w < 192; w++)
            {
                int A = RgbColor.fromArgbInt(pixelMap.readPixel(new Position(w,h))).getAlpha();
                RgbColor c = RgbColor.fromArgbInt(mColor);
                nPixelMap.writePixel(new Position(w,h),new RgbColor(c.getRed(),c.getGreen(),c.getBlue(),A).asArgbInt());
            }
        }
        return nPixelMap;
    }

    public static PixelMap coverIcon(PixelMap upperLayer,PixelMap lowerLayer)
    {
        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.size = new Size(192,192);
        initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
        initializationOptions.editable = true;
        PixelMap nPixelMap = PixelMap.create(initializationOptions);
        for (int h = 0; h < 192; h++)
        {
            for (int w = 0; w < 192; w++)
            {
                nPixelMap.writePixel(new Position(w,h),CalculateColorBlend(lowerLayer.readPixel(new Position(w,h)),upperLayer.readPixel(new Position(w,h))));
            }
        }
        return nPixelMap;
    }

    public static PixelMap resizeIcon(PixelMap icon,int size)
    {
        PixelMap.InitializationOptions initializationOptions_m = new PixelMap.InitializationOptions();
        initializationOptions_m.size = new Size(size,size);
        initializationOptions_m.pixelFormat = PixelFormat.ARGB_8888;
        initializationOptions_m.scaleMode = ScaleMode.FIT_TARGET_SIZE;
        initializationOptions_m.editable = true;
        PixelMap mPixelMap = PixelMap.create(icon,initializationOptions_m);
        PixelMap.InitializationOptions initializationOptions_n = new PixelMap.InitializationOptions();
        initializationOptions_n.size = new Size(192,192);
        initializationOptions_n.pixelFormat = PixelFormat.ARGB_8888;
        initializationOptions_n.editable = true;
        PixelMap nPixelMap = PixelMap.create(initializationOptions_n);
        int startPoint = (192-size)/2;
        int endPoint = 192-startPoint;
        for(int h = 0; h < 192; h++)
        {
            for(int w = 0; w < 192; w++)
            {
                if(h>=startPoint&&h<endPoint&&w>=startPoint&&w<endPoint)
                nPixelMap.writePixel(new Position(w,h),mPixelMap.readPixel(new Position(w-startPoint,h-startPoint)));
                else
                    nPixelMap.writePixel(new Position(w,h),new RgbColor(0,0,0,0).asArgbInt());
            }
        }
        return nPixelMap;
    }

    public static float CalculateBlend(float a1, float a2, float c1, float c2)
    {
        return (float)((c1 * a1 * (1.0 - a2) + c2 * a2) / (a1 + a2 - a1 * a2));
    }

    public static int CalculateColorBlend(int LowerLayerColor, int UpperLayerColor)
    {
        RgbColor LowerLayer = RgbColor.fromArgbInt(LowerLayerColor);
        RgbColor UpperLayer = RgbColor.fromArgbInt(UpperLayerColor);

        float AlphaValue01 = (float)LowerLayer.getAlpha() / 255f;
        float AlphaValue02 = (float)UpperLayer.getAlpha()/ 255f;
        float AlphaValueBlend = AlphaValue01 + AlphaValue02 - AlphaValue01 * AlphaValue02;
        int Alpha = (int)(AlphaValueBlend*255f+0.5f);

        float RedValue01 = (float)LowerLayer.getRed()/ 255f;
        float RedValue02 = (float)UpperLayer.getRed() / 255f;
        float RedValueBlend = CalculateBlend(AlphaValue01, AlphaValue02, RedValue01, RedValue02);
        int Red = (int)(RedValueBlend*255f+0.5f);

        float GreenValue01 = (float)LowerLayer.getGreen() / 255f;
        float GreenValue02 = (float)UpperLayer.getGreen() / 255f;
        float GreenValueBlend = CalculateBlend(AlphaValue01, AlphaValue02, GreenValue01, GreenValue02);
        int Green = (int)(GreenValueBlend*255f+0.5f);

        float BlueValue01 = (float)LowerLayer.getBlue() / 255f;
        float BlueValue02 = (float)UpperLayer.getBlue() / 255f;
        float BlueValueBlend = CalculateBlend(AlphaValue01, AlphaValue02, BlueValue01, BlueValue02);
        int Blue = (int)(BlueValueBlend*255f+0.5f);

        if (Alpha > 255) Alpha = 255;
        else if (Alpha < 0) Alpha = 0;
        if (Red > 255) Red = 255;
        else if (Red < 0) Red = 0;
        if (Green > 255f) Green = 255;
        else if (Green < 0f) Green = 0;
        if (Blue > 255f) Blue = 255;
        else if (Blue < 0f) Blue = 0;

        return new RgbColor(Red,Green,Blue,Alpha).asArgbInt();
    }

    public static PixelMap ResizeImage(PixelMap mPixelMap,int w,int h)
    {
        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.size = new Size(w,h);
        initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
        initializationOptions.scaleMode = ScaleMode.FIT_TARGET_SIZE;
        initializationOptions.editable = true;
        return PixelMap.create(mPixelMap,initializationOptions);
    }

    //鸿蒙自带的getBundleManager->getBundleInfos需要ohos.permission.GET_BUNDLE_INFO_PRIVILEGED权限
    //申请此权限，需要成为特权应用或系统级别签名，否则直接闪退不可用，这里通过java的反射机制实现！
    public static boolean ProcessAllAppIcons(AbilityContext abilityContext,int mColor, PixelMap foreground, PixelMap background, int size, PixelMap mask, String OutputPath, boolean fastMode)
    {
        try
        {
            Class<?> c_ActivityThread = Class.forName("android.app.ActivityThread");
            Class<?> ContextImpl  = Class.forName("android.app.ContextImpl");
            Class<?> c_Context = Class.forName("android.content.Context");
            Class<?> c_PackageInfo = Class.forName("android.content.pm.PackageInfo");
            Class<?> c_PackageManager = Class.forName("android.content.pm.PackageManager");
            Class<?> c_ApplicationInfo = Class.forName("android.content.pm.ApplicationInfo");

            Method m_systemMain = c_ActivityThread.getDeclaredMethod("systemMain");
            Method m_createSystemContext = ContextImpl.getDeclaredMethod("createSystemContext", c_ActivityThread);
            Method m_createPackageContext = c_Context.getMethod("createPackageContext",String.class,int.class);
            Method m_getPackageManager = c_Context.getDeclaredMethod("getPackageManager");
            Method m_getInstalledPackages = c_PackageManager.getDeclaredMethod("getInstalledPackages",int.class);
            Method m_loadIcon = c_ApplicationInfo.getMethod("loadIcon",c_PackageManager);

            m_createSystemContext.setAccessible(true);


            Object o_getPackageManager = null;
            if(SystemVersion.getApiVersion()<7)
            {
                Object object = m_systemMain.invoke(null);
                Object o_createSystemContext = m_createSystemContext.invoke(null, object);
                Object o_createPackageContext = m_createPackageContext.invoke(o_createSystemContext,"com.agger.harmonyosthemeseditor",1|2);
                o_getPackageManager = m_getPackageManager.invoke(o_createPackageContext);
            }else
            {
                o_getPackageManager = m_getPackageManager.invoke(GeneralUtil.getAbilityShellActivity(abilityContext));
            }
            Object o_getInstalledPackages = m_getInstalledPackages.invoke(o_getPackageManager,0);

            List<?> packages = (List<?>)o_getInstalledPackages;
            if(fastMode)
            {
                new File(OutputPath+"/dawnlighti_base").mkdirs();
                ImageIntelligent.saveImage(OutputPath+"/dawnlighti_base/foreground.png",foreground);
                ImageIntelligent.saveImage(OutputPath+"/dawnlighti_base/background.png",getVirtualBackground(mColor));
                for (Object packageInfo : packages)
                {
                    String appName = (String) c_PackageInfo.getField("packageName").get(packageInfo);
                    FileManager.copyDir(OutputPath + "/dawnlighti_base", OutputPath + "/" + appName);
                }
            }else
            {
                for (Object packageInfo : packages)
                {
                    String appName = (String) c_PackageInfo.getField("packageName").get(packageInfo);
                    Object applicationInfo = c_PackageInfo.getField("applicationInfo").get(packageInfo);
                    Object appIcon = m_loadIcon.invoke(applicationInfo, o_getPackageManager);
                    Object bm = GeneralUtil.drawableToBitmap(appIcon);
                    if (bm != null)
                    {
                        PixelMap pixelMap = ResizeImage(GeneralUtil.BitmaptoPixelMap(bm), 192, 192);
                        if (pixelMap != null)
                        {
                            pixelMap = resizeIcon(pixelMap, 142);
                            pixelMap = grayForPixelMap(pixelMap);
                            pixelMap = maskForIcon(mask, pixelMap);
                            pixelMap = colorfulIcon(mColor, pixelMap);
                            if (foreground != null)
                                pixelMap = coverIcon(foreground, pixelMap);
                            if (background != null)
                                pixelMap = coverIcon(pixelMap, background);
                            if (size != 192)
                                pixelMap = resizeIcon(pixelMap, size);
                            new File(OutputPath + "/" + appName).mkdirs();
                            ImageIntelligent.saveImage(OutputPath + "/" + appName + "/foreground.png", pixelMap);
                            ImageIntelligent.saveImage(OutputPath + "/" + appName + "/background.png", background);
                        }
                    }
                }
            }
            return true;
        }catch (Exception ex) {ex.printStackTrace(); return false;}
    }
}
